package redis

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis_rate/v10"
	"github.com/redis/go-redis/v9"
	"strconv"
	"sync"
	"time"
	"tools-api/src/common/def"
	"tools-api/src/common/utils"
)

var (
	redisClient      *redis.Client
	redisRateLimiter *redis_rate.Limiter
	ctx              = context.Background()
)

// once 确保全局的 Redis 对象只实例一次
var once sync.Once

// Connect 链接redis
func Connect() {
	once.Do(newRedisClient) // 保证只调用1次
}

// newRedisClient 创建
func newRedisClient() {
	config := def.Config.GetStringMap("redis")
	redisClient = redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%d", config["host"].(string), config["port"].(int)),
		Username: config["username"].(string),
		Password: config["password"].(string), // 没有密码，默认值
		DB:       config["db"].(int),          // 默认DB 0
	})

	_, err := redisClient.Ping(ctx).Result()
	if err != nil {
		panic(err)
	}
	redisRateLimiter = redis_rate.NewLimiter(redisClient) // 限速器
	fmt.Println("redis connect success")
}

// Set 存储 key 对应的 value，且设置 expiration 过期时间
func Set(key string, value interface{}, expiration time.Duration) bool {
	if err := redisClient.Set(ctx, key, value, expiration).Err(); err != nil {
		fmt.Println("redis set error", key)
		return false
	}
	return true
}

// Del 删除存储在 redis 里的数据，支持多个 key 传参
func Del(keys ...string) bool {
	if err := redisClient.Del(ctx, keys...).Err(); err != nil {
		fmt.Println("redis delete error", err.Error())
		return false
	}
	return true
}

// SetObj 存储对象
func SetObj(key string, value interface{}, expiration time.Duration) bool {
	str, err := utils.GobEncode(value)
	if err != nil {
		fmt.Println("redis set error", key)
		return false
	}
	return Set(key, str, expiration)
}

// GetObj 获取对象
func GetObj(key string, value interface{}) error {
	result, err := redisClient.Get(ctx, key).Bytes()
	if err != nil {
		return err
	}
	return utils.GobDecode(result, value)
}

// GetString 字符串类型
func GetString(key string) (string, error) {
	val, err := redisClient.Get(ctx, key).Result()
	if err != nil {
		return "", err
	}
	return val, nil
}

// GetInt int64类型
func GetInt(key string) (int64, error) {
	val, err := GetString(key)
	if err != nil {
		return 0, err
	}
	return strconv.ParseInt(val, 10, 64)
}

// Expire 重新设置过期时间间隔
func Expire(key string, expiration time.Duration) {
	redisClient.Expire(ctx, key, expiration)
}

// ExpireAt 重新指定过期时间
func ExpireAt(key string, tm time.Time) {
	redisClient.ExpireAt(ctx, key, tm)
}

// RateAllow 限速器处理
func RateAllow(ctx2 *gin.Context, key string, timesPerSecond int) bool {
	res, err := redisRateLimiter.Allow(ctx2, key, redis_rate.PerSecond(timesPerSecond))
	if err != nil || (res.Remaining < 0 || res.Allowed <= 0) {
		return false
	}
	return true
}

// Increase 计数+1
func Increase(key string) {
	redisClient.Incr(ctx, key)
}
